package com.ubxtech.sentinel.config;

import cn.hutool.core.util.StrUtil;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.SentinelWebInterceptor;
import com.alibaba.csp.sentinel.adapter.spring.webmvc.config.SentinelWebMvcConfig;
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
import com.alibaba.csp.sentinel.config.SentinelConfig;
import com.alibaba.csp.sentinel.transport.config.TransportConfig;
import com.ubxtech.sentinel.handler.CustomBlockExceptionHandler;
import com.ubxtech.sentinel.properties.SentinelProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import java.util.ArrayList;
import java.util.List;

/**
 *
 * @author Victor.Xiao
 * @since 2023-08-09 15:25
*/
@Configuration
@Slf4j
@EnableConfigurationProperties(SentinelProperties.class)
@ConditionalOnProperty(prefix = SentinelProperties.PREFIX, name = "enabled", havingValue = "true", matchIfMissing = true)
public class SentinelInterceptorConfig {

    @Resource
    private SentinelProperties sentinelProperties;

    @Value("${project.name:${spring.application.name:}}")
    private String projectName;


    @PostConstruct
    private void init() {
        if (StrUtil.isEmpty(System.getProperty(SentinelConfig.APP_NAME_PROP_KEY))
                && StrUtil.isNotBlank(projectName)) {
            System.setProperty(SentinelConfig.APP_NAME_PROP_KEY, projectName);
        }
        if (StrUtil.isEmpty(System.getProperty(TransportConfig.SERVER_PORT))
                && StrUtil.isNotBlank(sentinelProperties.getTransport().getPort())) {
            System.setProperty(TransportConfig.SERVER_PORT,
                    sentinelProperties.getTransport().getPort());
        }
        if (StrUtil.isEmpty(System.getProperty(TransportConfig.CONSOLE_SERVER))
                && StrUtil.isNotBlank(sentinelProperties.getTransport().getDashboard())) {
            System.setProperty(TransportConfig.CONSOLE_SERVER,
                    sentinelProperties.getTransport().getDashboard());
        }
        if (StrUtil.isEmpty(System.getProperty(TransportConfig.HEARTBEAT_INTERVAL_MS))
                && StrUtil
                .isNotBlank(sentinelProperties.getTransport().getHeartbeatIntervalMs())) {
            System.setProperty(TransportConfig.HEARTBEAT_INTERVAL_MS,
                    sentinelProperties.getTransport().getHeartbeatIntervalMs());
        }
        if (StrUtil.isEmpty(System.getProperty(TransportConfig.HEARTBEAT_CLIENT_IP))
                && StrUtil.isNotBlank(sentinelProperties.getTransport().getClientIp())) {
            System.setProperty(TransportConfig.HEARTBEAT_CLIENT_IP,
                    sentinelProperties.getTransport().getClientIp());
        }

//        InitExecutor.doInit();

    }


    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }

    @Bean
    public WebMvcConfigurer interceptorConfig() {
        return new WebMvcConfigurer() {

            @Override
            public void addInterceptors(InterceptorRegistry registry) {

                //簇点链路则不会出现改url
                List<String> excludePath = new ArrayList<>();
                if (sentinelProperties.getExcludePath() != null && sentinelProperties.getExcludePath().size() > 0) {
                    excludePath.addAll(sentinelProperties.getExcludePath());
                }
                List<String> includePath = new ArrayList<>();
                if (sentinelProperties.getIncludePath() != null && sentinelProperties.getIncludePath().size() > 0) {
                    includePath.addAll(sentinelProperties.getIncludePath());
                } else {
                    includePath.add("/**");
                }
                SentinelWebMvcConfig config = new SentinelWebMvcConfig();
                //在控制台簇点链路添加的能跑这里,但注解SentinelResource则会跑到ExceptionHandler中去,待研究
//                config.setBlockExceptionHandler(new CustomBlockExceptionHandler());
                //指定 请求方法 POST  GET 等等
                config.setHttpMethodSpecify(true);
                //默认使用统一Web上下文   如果希望支持链路关系的流控策略则应该设置为false
                config.setWebContextUnify(true);
                //用来标识来源 可针对性的对特定客户端的请求进行流控   limitApp
                //流控规则中提到的limitApp就是通过setOriginParser 来配置获取策略的。
                //待研究
//                config.setOriginParser(request -> request.getHeader("S-user"));

                InterceptorRegistration interceptorRegistration = registry.addInterceptor(new SentinelWebInterceptor(config));
                interceptorRegistration.addPathPatterns(includePath);
                if (excludePath.size() > 0) {
                    interceptorRegistration.excludePathPatterns(excludePath);
                }
            }

        };
    }


}
